本篇大綱:DOM 元素、SVG 重點概述、SVG 形狀/線條/路徑/文字、SVG樣式
上一章有提過在學習D3之前需要具備的知識,這邊就來講解其中最重要的一點:SVG!由於 D3.js 的畫面渲染部分是用 SVG 運作,因此如果完全不懂 SVG 的話,就無法順利使用 D3 了~現在來說說 SVG 是什麼吧!
在講SVG之前,我們需要先了解 html DOM樹 的概念。為什麼得要先了解DOM呢? 主要是因為 D3 是靠著操作 DOM 元素來進行node節點增減,再透過 SVG 去渲染圖表。
DOM 的全名是 Document Object Model,中文叫做文件物件模型。聽起來好像很複雜抽象,但其實就是把 HTML 文件中的每個標籤都定義成物件,最後這些物件會形成像是樹狀的結構。像下圖就是一個基本的html文件樹狀圖:
所以如果你的程式碼長這樣
<div>
    <div class="box">
        <div class="box1"></div>
        <div class="box2"></div>
    </div>
    <div class="list">
        <ul>
            <li></li>
            <li></li>
            <li></li>
        </ul>
    </div>
</div>
你的 DOM 樹結構就會是這樣
這裡的每一個 html 標籤就視為一個 node 節點,D3 是將數據資料綁定到節點,並增減節點來建立圖表。
有了以上的 DOM 概念後,我們就可以來看SVG啦!SVG 的全名是 Scale Vector Graphics (可縮放向量圖型),是以** XML 文字檔來建立 2D 的向量圖形**,因此開發者可以直接在 HTML 檔案中使用 SVG,而且也支援動畫跟互動的操作。
SVG 圖形可以有不同的形式
D3.js使用的就是第二種形式,在 html 檔案中使用svg標籤,並宣告它的空間範圍。接著在這個範圍內放入要繪製的圖形元素標籤,以及它的位置、顏色等等相關資訊
<svg width="500" height="500">
	 這邊放入要繪製的圖形元素標籤...
</svg>
了解SVG之後,我們來看一下SVG的一些基本概念
SVG 是基於 XML 文字檔格式,產生DOM樹 (不像canvas是平面畫布)
SVG 定義了一系列圖形元素,例如「圓或矩形等基本形狀、文字、直線、曲線」等等,然後再透過外觀屬性去改變這些形狀的尺寸、位置、顏色等等。
例如:svg 定義的 < rect > 矩形元素,< rect > 透過外觀屬形 x, y 去控制圖形位置;width, height 控制圖形大小;style 則控制邊框、顏色
<svg width="400" height="200" style="border:1px solid red">
    <rect x="20" y="20" width="300" height="100" 
          style="fill:rgb(255, 0, 255); stroke-width:3; stroke:rgb(0,0,0)" />
</svg>

結構元素,例如: < svg >、 < g >、< use >。大家在看別人的 svg 程式碼時,應該蠻常看到下圖  這個元素,它就是其中一種 SVG 的結構元素 
那你可能就會問,什麼是結構元素呢?結構元素是一種容器元素,不會繪製外型,而是用來包裹多個子元素,這樣一來就能將其下的子元素包成一個大包的共同元素,統一去改變位置、形狀或顏色等等。
我們可以簡單整理一下結構元素的特點:
後來寫的元素會遮蓋掉先前出現的元素
原點是左上角,由上而下、從左至右回應事件進行互動
原則上是無限大,width / height 只是定義 viewport (可視範圍)。
但是不可能所有數據都剛好符合我們設定的視窗比例,這也正是為什麼、要定義比例尺的原因。透過比例尺去定義出視窗大小跟數據的比例,才能將繪製完的圖形完整放到我們的 svg 視窗內。
看完這些之後,相信大家對 SVG 已經有概念了。接下來我們來看看 SVG 定義的一些形狀、線條、路徑,以及它們的屬性吧!
svg 已經先幫我們定義好一些形狀,並賦予相對應的標籤。我們只要使用這些標籤,並添加固定的屬性,就可以畫出一些基本的形狀啦~這些定義好的形狀包含:
< rect > 矩形
| 屬性 | 意義 | 
|---|---|
| x, y | 左上角座標寬、高 | 
| width, height | 寬高 | 
| rx, ry | 水平/垂直邊角半徑 | 
範例:從坐標軸 x 20 與 y 20 的地方開始,建立一個寬300、高100的長方形;內部填滿桃紅色,並且要有3px的粗黑邊框
<svg width="400" height="200" style="border:1px solid red">
    <rect x="20" y="20" width="300" height="100" 
          style="fill:rgb(255, 0, 255); stroke-width:3; stroke:rgb(0,0,0)" />
</svg>

< circle > 圓形
| 屬性 | 意義 | 
|---|---|
| cx, cy | 水平/垂直中心座標 | 
| r | 半徑 | 
範例:從坐標軸 x 100 與 y 50 的地方開始,建立一個半徑為40的圓型,內部填滿紅色,且要有3px的粗黑邊框
<svg width="400" height="150" style="border:1px solid red">
  <circle cx="100" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>

< ellipse > 橢圓形
| 屬性 | 意義 | 
|---|---|
| cx, cy | 中心座標水平 | 
| rx, ry | 垂直半徑 | 
範例:從坐標軸 x 200 與 y 80 的地方開始,建立一個x半徑為80、y半徑為50的橢圓型,內部填滿淡粉紅色,且要有3px的粗黑邊框
<svg width="400" height="150">
  <ellipse cx="200" cy="80" rx="80" ry="50" stroke="black" stroke-width="3" fill="pink"></ellipse>
</svg>

< line > 線條
| 屬性 | 意義 | 
|---|---|
| x1, x2 | 座標開始點 | 
| y1, y2 | 座標結束點 | 
範例:繪製第一端在圓點( x0, y0 ),另外一端在( x200, y200 )的直線,粗度為2px
<svg width="400" height="200">
  <line x1="0" y1="0" x2="200" y2="200" style="stroke:rgb(0,0,255); stroke-width:2" />
</svg>

< polyline > 折線
| 屬性 | 意義 | 
|---|---|
| points | 表示每個點之間的 X、Y 座標 | 
範例:繪製端點 20,50 40,25 60,40 80,120 120,140 160,180 的折線,粗度為3px
<svg width="400" height="200">
    <polyline
      points="20,50 40,25 60,40 80,120 120,140 160,180 "
      style="fill: none; stroke: orangered; stroke-width: 3"
    />
  </svg>

< polygon > 多邊形| 屬性 | 意義 | 
|---|---|
| points | 表示每個點之間的 X、Y 座標 | 
範例:繪製端點 200,10 250,190 160,180 的閉合形狀,顏色填滿為綠色,邊框粗度為3px
<svg width="400" height="200">
  <polygon
    points="200,10 250,190 160,180"
    style="fill: lime; stroke: purple; stroke-width: 1"
  />
</svg>

< path > 路徑
| 屬性 | 意義 | 
|---|---|
| d | 路徑 | 
< path > 元素是在 SVG 中最常見的指令,它可以透過命令語言繪製任何形狀。它只有一個 d 屬性,而屬性值是由「空白間隔的命令」+「座標字串」組合而成。
所有的「空白間隔的命令」都是用一個英文字元指令,並具備兩種形式
習慣上在一開始時,會用 M 命令移動到一個明確的位置再開始繪製。至於座標的部分,在 < path > 中的座標都沒有單位,而且可以有負值。
以下列出幾個常見的命令英文代號,但由於繪製路徑很複雜,一般我們不會自己算座標去畫圖,而是使用一些輔助工具 (例如 AI illustrator) 畫好圖片後存成SVG檔,而D3.js 也提供了函式去產生相對應的路徑。
命令英文代號
M, m  移動至特定位置 (不會繪製線條)L, l  畫一條直線到...H, h 水平線V, v 垂直線Z, z 把目前座標的點跟第一點連起來,並形成封閉路徑C, c  立方貝茲曲線S, s 從多個控制點畫立方貝茲曲線Q, q 畫貝茲曲線T, t 從多個控制點畫貝茲曲線A, a 從目前的位置畫橢圓曲線<svg width="400" height="200">
  <path
    d="M50 20 C80 90,40 200,250,100"
    stroke="black"
    fill="none"
    stroke-width="2"
  />
</svg>

也可以透過不同線段畫出有趣的圖
<svg width="100" height="100">
    <path
      d="M25,15 L25,30
         M75,15 L75,30
         M15,50 C20,80 80,80 85,50"
      stroke="black"
      fill="none"
      stroke-width="2"
    />
</svg>

< text > 文字
| 屬性 | 意義 | 
|---|---|
| x,y | 文字的座標 | 
| dx | 以 x 座標為基準,平行移動文字距離(正為往右,負為往左)。 | 
| dy | 以 Y 座標為基準,垂直移動文字距離(正為往上,負為往下)。 | 
| textLength | 設定這段文字的長度,和 lengthAdjust ( 設定對這段文字長度的調整 ) 搭配運作 | 
| text-anchor | 文字開始繪製位置 (靠左、置中、靠右對齊) | 
| rotate | 每個文字的旋轉角度,若是要整組文字一起旋轉可以使用 transform="rotate()" | 
特別的是,只要把屬形值改為陣列 [ ] ,這些屬性就可以針對單一字元設定。
<svg width="400" height="200">
    <text x="50,60,80" y="80,120,40" fill="blue" text-anchor="start">
      SVG 真有趣!
    </text>
</svg>

看完上述SVG定義的圖形後,會發現這些標籤還跟著很多屬性的設定。有了這些屬性,我們才能設定形狀的樣式、動畫等等,以下就來介紹一些常見的屬性:
常用表現屬性:
| 常用表現屬性 | 用途 | 
|---|---|
| < stroke > | 圖形的邊框顏色 | 
| < stroke-width > | 圖形的邊框粗細 | 
| < fill > | 圖形的內部填滿顏色 | 
| < font-size > | 文字尺寸 | 
| < opacity > | 圖形的透明度 | 
| < visibility > | 圖形是否可視 | 
.
轉換屬性:移動、旋轉、延展、推移
| 常用轉換屬性 | 用途 | 
|---|---|
| < rotate > | 圖形旋轉 | 
| < transform > | 圖形變形 | 
.
如果看完這邊後,想再更深入了解SVG的話,可以參考 W3C的SVG教學 ,裡面根據每個SVG的圖形跟樣式都有個別說明~
關於SVG的屬性,我這邊只介紹一些比較常用的~如果想看完整的屬性列表,則可以到MDN的頁面查找
.
最後,這邊附上本章的程式碼與圖表 Github 、 Github Page,需要的人請自行取用~
今天終於平安的結束啦~明天再見!